---
title: Pin Input
description: Using the pin input machine in your project.
package: "@zag-js/pin-input"
---

The pin input is optimized for entering a sequence of digits or letters. The
input fields allow one character at a time. When the digit or letter is entered,
focus transfers to the next input in the sequence, until every input is filled.

<Resources pkg="@zag-js/pin-input" />

<Showcase id="PinInput" />

**Features**

- Automatically focuses the next field on typing and focuses the previous field
  on deletion
- Supports numeric and alphanumeric values
- Support for masking value (for sensitive data)
- Support for copy/paste to autofill all fields
- Supports fast paste SMS-code

## Installation

To use the pin input machine in your project, run the following command in your
command line:

<CodeSnippet id="pin-input/installation.mdx" />

## Anatomy

To set up the pin input correctly, you'll need to understand its anatomy and how
we name its parts.

> Each part includes a `data-part` attribute to help identify them in the DOM.

<Anatomy id="pin-input" />

## Usage

First, import the pin input package into your project

```jsx
import * as pinInput from "@zag-js/pin-input"
```

The pin input package exports two key functions:

- `machine` — The state machine logic for the pin input widget.
- `connect` — The function that translates the machine's state to JSX attributes
  and event handlers.

> You'll need to provide a unique `id` to the `useMachine` hook. This is used to
> ensure that the every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the pin
input machine in your project 🔥

<CodeSnippet id="pin-input/usage.mdx" />

### Setting a default value

Use the `defaultValue` context property to set the initial value of the pin
input. The value must be an array of strings.

```jsx {2}
const service = useMachine(pinInput.machine, {
  defaultValue: ["1", "2", ""],
})
```

### Controlled value

Use the `value` and `onValueChange` properties to programmatically control the
value of the pin input.

<CodeSnippet id="pin-input/controlled.mdx" />

### Changing the placeholder

To customize the default pin input placeholder (○) for each input, pass the
`placeholder` prop and set it to your desired value.

```jsx {2}
const service = useMachine(pinInput.machine, {
  placeholder: "*",
})
```

### Blur on complete

By default, the last input maintains focus when filled and we invoke the
`onComplete` callback. To blur the last input when the user completes the input,
set the `blurOnComplete: true` in the machine's context.

```jsx {2}
const service = useMachine(pinInput.machine, {
  blurOnComplete: true,
})
```

### Allowing alphanumeric values

By default, the pin input accepts only number values but you can choose between
`numeric`, `alphanumeric` and `alphabetic` values. To change the input mode,
pass the `type` context property and set its value to `alphanumeric`.

```jsx {2}
const service = useMachine(pinInput.machine, {
  type: "alphanumeric",
})
```

### Using OTP mode

To trigger smartphone OTP auto-suggestion, it is recommended to set the
`autocomplete` attribute to "one-time-code". The pin-input machine provides
support for this automatically when you set the `otp` context property to
`true`.

```jsx {2}
const service = useMachine(pinInput.machine, {
  otp: true,
})
```

### Securing the text input

When collecting private or sensitive information using the pin input, you might
need to mask the value entered, similar to `<input type="password"/>`. Pass the
`mask` context property and set it to `true`.

```jsx {2}
const service = useMachine(pinInput.machine, {
  mask: true,
})
```

### Listening for changes

The pin input machine invokes several callback functions when the user enters:

- `onValueChange` — Function invoked when the value is changed.
- `onValueComplete` — Function invoked when all fields have been completed (by
  typing or pasting).
- `onValueInvalid` — Function invoked when an invalid value is entered into the
  input. An invalid value is any value that doesn't match the specified "type".

```jsx
const service = useMachine(pinInput.machine, {
  onValueChange(value) {
    // value => string[]
    console.log("value changed to:", value)
  },
  onValueComplete(details) {
    // details => { value: string[], valueAsString: string }
    console.log("completed value:", details)
  },
  onValueInvalid(details) {
    // details => { index: number, value: string }
    console.log("invalid value:", details)
  },
})
```

### RTL support

The pin input machine supports RTL writing directions. To set the `dir` property
in the machine's context.

When this attribute is set, we attach a `dir` attribute to the root part.

```jsx {2}
const service = useMachine(pinInput.machine, {
  dir: "rtl",
})
```

## Styling guide

Earlier, we mentioned that each pin input's part has a `data-part` attribute
added to them to select and style them in the DOM.

### Completed state

When all values have been filled, we attach a `data-complete` attribute to the
root and input parts.

```css
[data-part="root"][data-complete] {
  /* styles for when all value has been filled */
}

[data-part="input"][data-complete] {
  /* styles for when all value has been filled */
}
```

### Invalid state

When an invalid value is entered, we attach a `data-invalid` attribute to the
affected input part.

```css
[data-part="input"][data-invalid] {
  /* styles for when the input is invalid */
}
```

### Disabled state

When the pin-input is disabled, we attach a `data-disabled` attribute to the
root and input parts.

```css
[data-part="root"][data-disabled] {
  /* styles for when the input is disabled */
}

[data-part="input"][data-invalid] {
  /* styles for when the input is disabled */
}
```

## Methods and Properties

### Machine Context

The pin input machine exposes the following context properties:

<ContextTable name="pin-input" />

### Machine API

The pin input `api` exposes the following methods:

<ApiTable name="pin-input" />

### Data Attributes

<DataAttrTable name="pin-input" />

## Accessibility

### Keyboard Interactions

<KeyboardTable name="pin-input" />
